import {article, section} from './lablog.js'
import _ from 'lodash'


section(`
functor 的概念来自于范畴学，并满足一些定律：
map(id) === id
compose(map(f), map(g)) === map(compose(f, g))
同一律很简单，但是也很重要。因为这些定律都是可以运行的代码。
`)

const map = _.curry(function(f, functor) {
    return functor.map(f)
})

const ID = function(x) {this.__value = x}
ID.of = function(x) {return new ID(x)}
ID.prototype.map = function(f) {
    return ID.of(f(this.__value))
}
const id = x => x
const idLaw1 = map(id)
const idLaw2 = id

console.log("idLaw1", idLaw1(ID.of(2)))
console.log("idLaw2", idLaw2(ID.of(2)))
console.log(idLaw1(ID.of(3)).__value === idLaw2(ID.of(3)).__value)
/*
idLaw1: 
map(id)
(functor) => functor.map(id)
(functor) => ID.of(id(functor.__value))
(functor) => ID.of(functor.__value)

idLaw2:
x => x
functor(2) => functor(2)
*/
const concat = _.curryRight((x, y) => `${x}${y}`)
const compLaw1 = _.flowRight(map(concat(" world")), map(concat(" cruel")))
const compLaw2 = map(_.flowRight(concat(" world"), concat(" cruel")))
console.log(compLaw1(ID.of('Goodbye')))
console.log(compLaw2(ID.of('Goodbye')))
/*
compLaw1:
flow(map(concat("1")), map(concat("2")))
function(functorP) {
    map(concat(1), map(concat("2"), functorP))
}
function(functorP) {
    map(concat(1), functor(concat(2), functorP.v))
}
function(functorP) {
    functor(concat(1), functor(concat(2), functorP.v))
}

compLaw2:
map(flow(concat(1), concat(2)))
map(function(functorP) => {
    concat(1)(concat(2)(functorP))
})
function(functor) {
    functor(function(functorP) => {
        concat(1)(concat(2)(functorP))
    })
}
function(functor) {
    functor(
        concat(1)(functor(concat(2), functorP.v))
        // =>
        functor(concat(1), functor(concat(2), functorP.v))
    )
}
*/
section(`
范畴学中，functor 接受一个范畴的对象和态射。然后将它们映射(map)到另一个范畴里去。根据定义，这个新范畴一定会有一个单位元，也一定能够组合态射。我们无需验证这一点，上面的定律会保证这些东西在映射后得到保留

`)